/**
 ******************************************************************************
 * @file           : bsp_tim_pwm.c
 * @brief          : Timer PWM Driver Implementation
 ******************************************************************************
 * @attention
 *
 * 定时器PWM驱动程序实现
 * 支持高级定时器（TIM1, TIM8）和通用定时器（TIM2-5）的PWM输出功能
 * 提供多通道PWM控制接口
 *
 * 适配平台：STM32F1xx
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "./BSP/TIMER/bsp_tim_pwm.h"

/* ============================================================================ */
/*                          日志配置（用户可修改）                               */
/* ============================================================================ */
/* 日志后端选择：1=EasyLogger, 2=printf, 0=关闭 */
#define PWM_USE_LOG     0

#if (PWM_USE_LOG == 1)
    /* 使用EasyLogger */
    #ifndef LOG_TAG
        #define LOG_TAG    "TIM_PWM"
    #endif
    #include "elog.h"
    
#elif (PWM_USE_LOG == 2)
    /* 使用printf */
    #include <stdio.h>
    #define log_i(fmt, ...)     printf(fmt "\r\n", ##__VA_ARGS__)
    #define log_w(fmt, ...)     printf("[WARN] " fmt "\r\n", ##__VA_ARGS__)
    #define log_e(fmt, ...)     printf("[ERROR] " fmt "\r\n", ##__VA_ARGS__)
    #define log_d(fmt, ...)     printf("[DEBUG] " fmt "\r\n", ##__VA_ARGS__)
    
#else
    /* 关闭日志 */
    #define log_i(fmt, ...)
    #define log_w(fmt, ...)
    #define log_e(fmt, ...)
    #define log_d(fmt, ...)
#endif

/* ============================================================================ */
/*                          定时器配置（条件编译）                               */
/* ============================================================================ */

#ifdef PWM_TIM_USE_TIM1
    #define PWM_TIMx                        TIM1
    #define PWM_TIMx_CLK_ENABLE()           __HAL_RCC_TIM1_CLK_ENABLE()
#endif

#ifdef PWM_TIM_USE_TIM2
    #define PWM_TIMx                        TIM2
    #define PWM_TIMx_CLK_ENABLE()           __HAL_RCC_TIM2_CLK_ENABLE()
#endif

#ifdef PWM_TIM_USE_TIM3
    #define PWM_TIMx                        TIM3
    #define PWM_TIMx_CLK_ENABLE()           __HAL_RCC_TIM3_CLK_ENABLE()
#endif

#ifdef PWM_TIM_USE_TIM4
    #define PWM_TIMx                        TIM4
    #define PWM_TIMx_CLK_ENABLE()           __HAL_RCC_TIM4_CLK_ENABLE()
#endif

#ifdef PWM_TIM_USE_TIM5
    #define PWM_TIMx                        TIM5
    #define PWM_TIMx_CLK_ENABLE()           __HAL_RCC_TIM5_CLK_ENABLE()
#endif

#ifdef PWM_TIM_USE_TIM8
    #define PWM_TIMx                        TIM8
    #define PWM_TIMx_CLK_ENABLE()           __HAL_RCC_TIM8_CLK_ENABLE()
#endif

/* Private includes ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef g_tim_pwm_handle = {0};               /*!< PWM定时器句柄 */

static uint8_t s_pwm_initialized = 0;                   /*!< 初始化标志 */

/* Private function prototypes -----------------------------------------------*/
static void tim_pwm_gpio_init(void);
static uint32_t tim_pwm_get_channel(PWM_Channel_e channel);

/* Private functions ---------------------------------------------------------*/

/**
 * @brief       PWM GPIO初始化
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        配置PWM输出引脚为复用推挽输出
 */
static void tim_pwm_gpio_init(void)
{
    GPIO_InitTypeDef gpio_init = {0};
    
    /* 使能GPIO时钟 */
    PWM_GPIO_CLK_ENABLE();
    
    /* 配置PWM输出引脚 */
    gpio_init.Pin = PWM_CH1_PIN | PWM_CH2_PIN | PWM_CH3_PIN | PWM_CH4_PIN;
    gpio_init.Mode = GPIO_MODE_AF_PP;
    gpio_init.Pull = GPIO_NOPULL;
    gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;
    
    HAL_GPIO_Init(PWM_GPIO_PORT, &gpio_init);
}

/**
 * @brief       获取HAL库通道宏定义
 *
 * @param[in]   channel 通道枚举
 *
 * @retval      HAL库通道宏
 */
static uint32_t tim_pwm_get_channel(PWM_Channel_e channel)
{
    switch (channel)
    {
        case PWM_CHANNEL_1: return TIM_CHANNEL_1;
        case PWM_CHANNEL_2: return TIM_CHANNEL_2;
        case PWM_CHANNEL_3: return TIM_CHANNEL_3;
        case PWM_CHANNEL_4: return TIM_CHANNEL_4;
        default: return TIM_CHANNEL_1;
    }
}

/* Exported functions --------------------------------------------------------*/

/**
 * @brief       PWM初始化
 *
 * @param[in]   freq PWM频率（Hz）
 * @param[in]   duty 占空比（0~100）
 *
 * @retval      无
 *
 * @note        STM32F1: TIM2-5时钟 = 72MHz（APB1预分频后倍频）
 * @note        频率 = 72MHz / (psc+1) / (arr+1)
 */
void tim_pwm_init(uint32_t freq, uint8_t duty)
{
    TIM_OC_InitTypeDef oc_config = {0};
    uint32_t timer_clock;
    uint32_t prescaler;
    uint32_t period;
    uint32_t pulse;
    HAL_StatusTypeDef hal_status;
    
    if (s_pwm_initialized)
    {
        log_w("PWM already initialized");
        return;
    }
    
    /* 参数检查 */
    if (freq == 0)
    {
        log_w("Invalid freq=0, use default %d Hz", PWM_DEFAULT_FREQ);
        freq = PWM_DEFAULT_FREQ;
    }
    if (duty > 100)
    {
        log_w("Invalid duty=%d%%, use default %d%%", duty, PWM_DEFAULT_DUTY);
        duty = PWM_DEFAULT_DUTY;
    }
    
    log_i("PWM Init: freq=%d Hz, duty=%d%%", freq, duty);
    
    /* 使能定时器时钟 */
    PWM_TIMx_CLK_ENABLE();
    
    /* 配置GPIO */
    tim_pwm_gpio_init();
    
    /*
     * STM32F1时钟配置：
     * HCLK = SYSCLK = 72MHz
     * PCLK1 = HCLK / 2 = 36MHz
     * TIM2-5时钟 = PCLK1 x 2 = 72MHz
     */
    timer_clock = SystemCoreClock / 2;  /* 72MHz */
    
    /*
     * 计算分频和周期值
     * 目标：freq = timer_clock / (psc+1) / (arr+1)
     * 
     * 策略：
     * - 优先保证周期分辨率（arr尽量大）
     * - psc从1开始，arr从65535递减
     */
    prescaler = 1;
    period = timer_clock / (prescaler + 1) / freq - 1;
    
    /* 如果周期超过16位最大值，增加预分频 */
    while (period > 65535)
    {
        prescaler++;
        period = timer_clock / (prescaler + 1) / freq - 1;
    }
    
    /* 计算脉冲宽度（占空比） */
    pulse = (period + 1) * duty / 100;
    
    /* 配置定时器基本参数 */
    g_tim_pwm_handle.Instance = PWM_TIMx;
    g_tim_pwm_handle.Init.Prescaler = prescaler;
    g_tim_pwm_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
    g_tim_pwm_handle.Init.Period = period;
    g_tim_pwm_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    g_tim_pwm_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    
    hal_status = HAL_TIM_PWM_Init(&g_tim_pwm_handle);
    if (hal_status != HAL_OK)
    {
        log_e("HAL_TIM_PWM_Init failed: %d", hal_status);
        return;
    }
    
    /* 配置PWM输出通道 */
    oc_config.OCMode = TIM_OCMODE_PWM1;
    oc_config.Pulse = pulse;
    oc_config.OCPolarity = TIM_OCPOLARITY_HIGH;
    oc_config.OCFastMode = TIM_OCFAST_DISABLE;
    
    /* 配置4个通道 */
    HAL_TIM_PWM_ConfigChannel(&g_tim_pwm_handle, &oc_config, TIM_CHANNEL_1);
    HAL_TIM_PWM_ConfigChannel(&g_tim_pwm_handle, &oc_config, TIM_CHANNEL_2);
    HAL_TIM_PWM_ConfigChannel(&g_tim_pwm_handle, &oc_config, TIM_CHANNEL_3);
    HAL_TIM_PWM_ConfigChannel(&g_tim_pwm_handle, &oc_config, TIM_CHANNEL_4);
    
    s_pwm_initialized = 1;
    log_i("PWM Init OK: psc=%d, arr=%d", prescaler, period);
}

/**
 * @brief       PWM反初始化
 *
 * @param       无
 *
 * @retval      无
 */
void tim_pwm_deinit(void)
{
    if (!s_pwm_initialized)
    {
        log_w("PWM not initialized");
        return;
    }
    
    /* 停止所有PWM通道 */
    tim_pwm_stop(PWM_CHANNEL_ALL);
    
    /* 反初始化定时器 */
    HAL_TIM_PWM_DeInit(&g_tim_pwm_handle);
    
    s_pwm_initialized = 0;
    log_i("PWM DeInit OK");
}

/**
 * @brief       启动PWM输出
 *
 * @param[in]   channel PWM通道
 *
 * @retval      无
 */
void tim_pwm_start(PWM_Channel_e channel)
{
    if (!s_pwm_initialized)
    {
        log_e("PWM not initialized");
        return;
    }
    
    if (channel > PWM_CHANNEL_ALL)
    {
        log_e("Invalid channel: %d", channel);
        return;
    }
    
    if (channel == PWM_CHANNEL_ALL)
    {
        HAL_TIM_PWM_Start(&g_tim_pwm_handle, TIM_CHANNEL_1);
        HAL_TIM_PWM_Start(&g_tim_pwm_handle, TIM_CHANNEL_2);
        HAL_TIM_PWM_Start(&g_tim_pwm_handle, TIM_CHANNEL_3);
        HAL_TIM_PWM_Start(&g_tim_pwm_handle, TIM_CHANNEL_4);
    }
    else
    {
        HAL_TIM_PWM_Start(&g_tim_pwm_handle, tim_pwm_get_channel(channel));
    }
}

/**
 * @brief       停止PWM输出
 *
 * @param[in]   channel PWM通道
 *
 * @retval      无
 */
void tim_pwm_stop(PWM_Channel_e channel)
{
    if (!s_pwm_initialized)
    {
        log_e("PWM not initialized");
        return;
    }
    
    if (channel > PWM_CHANNEL_ALL)
    {
        log_e("Invalid channel: %d", channel);
        return;
    }
    
    if (channel == PWM_CHANNEL_ALL)
    {
        HAL_TIM_PWM_Stop(&g_tim_pwm_handle, TIM_CHANNEL_1);
        HAL_TIM_PWM_Stop(&g_tim_pwm_handle, TIM_CHANNEL_2);
        HAL_TIM_PWM_Stop(&g_tim_pwm_handle, TIM_CHANNEL_3);
        HAL_TIM_PWM_Stop(&g_tim_pwm_handle, TIM_CHANNEL_4);
    }
    else
    {
        HAL_TIM_PWM_Stop(&g_tim_pwm_handle, tim_pwm_get_channel(channel));
    }
}

/**
 * @brief       设置PWM占空比
 *
 * @param[in]   channel PWM通道
 * @param[in]   duty 占空比（0~100）
 *
 * @retval      无
 */
void tim_pwm_set_duty(PWM_Channel_e channel, uint8_t duty)
{
    uint16_t period;
    uint16_t pulse;
    
    if (!s_pwm_initialized)
    {
        log_e("PWM not initialized");
        return;
    }
    
    if (channel >= PWM_CHANNEL_ALL)
    {
        log_e("Invalid channel: %d", channel);
        return;
    }
    
    if (duty > 100)
    {
        log_w("Invalid duty=%d%%, clamp to 100%%", duty);
        duty = 100;
    }
    
    /* 计算脉冲宽度 */
    period = __HAL_TIM_GET_AUTORELOAD(&g_tim_pwm_handle);
    pulse = (period + 1) * duty / 100;
    
    /* 设置比较值 */
    if (channel == PWM_CHANNEL_ALL)
    {
        __HAL_TIM_SET_COMPARE(&g_tim_pwm_handle, TIM_CHANNEL_1, pulse);
        __HAL_TIM_SET_COMPARE(&g_tim_pwm_handle, TIM_CHANNEL_2, pulse);
        __HAL_TIM_SET_COMPARE(&g_tim_pwm_handle, TIM_CHANNEL_3, pulse);
        __HAL_TIM_SET_COMPARE(&g_tim_pwm_handle, TIM_CHANNEL_4, pulse);
    }
    else
    {
        __HAL_TIM_SET_COMPARE(&g_tim_pwm_handle, tim_pwm_get_channel(channel), pulse);
    }
}

/**
 * @brief       设置PWM频率
 *
 * @param[in]   freq PWM频率（Hz）
 *
 * @retval      无
 *
 * @note        会重新计算预分频和周期值
 * @note        所有通道的占空比保持不变
 */
void tim_pwm_set_freq(uint32_t freq)
{
    uint32_t timer_clock;
    uint32_t prescaler;
    uint32_t period;
    uint16_t old_period;
    uint16_t pulse[4];
    uint8_t i;
    
    if (!s_pwm_initialized)
    {
        log_e("PWM not initialized");
        return;
    }
    
    if (freq == 0)
    {
        log_e("Invalid freq=0");
        return;
    }
    
    log_d("Set PWM freq: %d Hz", freq);
    
    /* 保存当前占空比 */
    old_period = __HAL_TIM_GET_AUTORELOAD(&g_tim_pwm_handle);
    pulse[0] = __HAL_TIM_GET_COMPARE(&g_tim_pwm_handle, TIM_CHANNEL_1);
    pulse[1] = __HAL_TIM_GET_COMPARE(&g_tim_pwm_handle, TIM_CHANNEL_2);
    pulse[2] = __HAL_TIM_GET_COMPARE(&g_tim_pwm_handle, TIM_CHANNEL_3);
    pulse[3] = __HAL_TIM_GET_COMPARE(&g_tim_pwm_handle, TIM_CHANNEL_4);
    
    /* 计算新的分频和周期值 */
    timer_clock = SystemCoreClock / 2;
    prescaler = 1;
    period = timer_clock / (prescaler + 1) / freq - 1;
    
    while (period > 65535)
    {
        prescaler++;
        period = timer_clock / (prescaler + 1) / freq - 1;
    }
    
    /* 更新预分频和周期 */
    __HAL_TIM_SET_PRESCALER(&g_tim_pwm_handle, prescaler);
    __HAL_TIM_SET_AUTORELOAD(&g_tim_pwm_handle, period);
    
    /* 按比例调整脉冲宽度，保持占空比不变 */
    for (i = 0; i < 4; i++)
    {
        pulse[i] = (uint16_t)((uint32_t)pulse[i] * (period + 1) / (old_period + 1));
    }
    
    __HAL_TIM_SET_COMPARE(&g_tim_pwm_handle, TIM_CHANNEL_1, pulse[0]);
    __HAL_TIM_SET_COMPARE(&g_tim_pwm_handle, TIM_CHANNEL_2, pulse[1]);
    __HAL_TIM_SET_COMPARE(&g_tim_pwm_handle, TIM_CHANNEL_3, pulse[2]);
    __HAL_TIM_SET_COMPARE(&g_tim_pwm_handle, TIM_CHANNEL_4, pulse[3]);
}

/**
 * @brief       设置PWM脉冲宽度
 *
 * @param[in]   channel PWM通道
 * @param[in]   pulse 脉冲宽度（0 ~ period）
 *
 * @retval      无
 *
 * @note        直接设置比较值，适合高级应用
 */
void tim_pwm_set_pulse(PWM_Channel_e channel, uint16_t pulse)
{
    uint16_t period;
    
    if (!s_pwm_initialized)
    {
        return;
    }
    
    /* 参数检查 */
    period = __HAL_TIM_GET_AUTORELOAD(&g_tim_pwm_handle);
    if (pulse > period)
    {
        pulse = period;
    }
    
    /* 设置比较值 */
    if (channel == PWM_CHANNEL_ALL)
    {
        __HAL_TIM_SET_COMPARE(&g_tim_pwm_handle, TIM_CHANNEL_1, pulse);
        __HAL_TIM_SET_COMPARE(&g_tim_pwm_handle, TIM_CHANNEL_2, pulse);
        __HAL_TIM_SET_COMPARE(&g_tim_pwm_handle, TIM_CHANNEL_3, pulse);
        __HAL_TIM_SET_COMPARE(&g_tim_pwm_handle, TIM_CHANNEL_4, pulse);
    }
    else
    {
        __HAL_TIM_SET_COMPARE(&g_tim_pwm_handle, tim_pwm_get_channel(channel), pulse);
    }
}

/**
 * @brief       获取PWM脉冲宽度
 *
 * @param[in]   channel PWM通道
 *
 * @retval      脉冲宽度值
 */
uint16_t tim_pwm_get_pulse(PWM_Channel_e channel)
{
    if (!s_pwm_initialized || channel == PWM_CHANNEL_ALL)
    {
        return 0;
    }
    
    return __HAL_TIM_GET_COMPARE(&g_tim_pwm_handle, tim_pwm_get_channel(channel));
}

/**
 * @brief       获取PWM周期值
 *
 * @param       无
 *
 * @retval      周期值
 */
uint16_t tim_pwm_get_period(void)
{
    if (!s_pwm_initialized)
    {
        return 0;
    }
    
    return __HAL_TIM_GET_AUTORELOAD(&g_tim_pwm_handle);
}
